/**
* @brief
*       Find errors and decrease probability of getting errors of the same kind in the future
*       This piece of code won't compile and it doesn't describe an entire algorithm: just part of some page storage
*
* @author
*       AnnaM
*/

//#include <Windows.h>   
#include <stdio.h>
#include <string.h>   // FIXME: string.h is necessairy for memset()

#define CHAR char
#define UINT unsigned int
enum PAGE_COLOR
{
    PG_COLOR_GREEN = 1, /* page may be released without high overhead */
    PG_COLOR_YELLOW,    /* nice to have */    
    PG_COLOR_RED        /* page is actively used */ 
};

// Numeration should start from 0! Because 

/**
 * UINT Key of a page in hash-table (prepared from color and address)
 */
union PageKey
{
    struct 
    {
        CHAR    cColor: 8;
        UINT    cAddr: 24;
    };

    UINT    uKey;
};


/* Prepare from 2 chars the key of the same configuration as in PageKey */
#define CALC_PAGE_KEY( Addr, Color )    ((Color) + ((Addr) << 8) ) // FIXME: "+" has higher priority than "<<"


/**
 * Descriptor of a single guest physical page
 */
typedef struct PageDesc // FIXME: typedef lets us reference struct PageDesc without "struct" word
{
    PageKey         uKey;   

    /* list support */
    PageDesc        *next, *prev; 
} PageDesc;


#define PAGE_INIT ( Desc, Addr, Color )                 \
    do {                                                \// FIXME: do while is necessairy here because otherwise
                                                        \//     in case of "if-else"-block  it will cause a syntax error
        Desc->uKey = CALC_PAGE_KEY( Addr, Color );      \    
        Desc->next = NULL; Desc->prev = NULL; }         \// FIXME: Desc is a pointer (string 101), so "->" should be used
    while(0);
        

/* storage for pages of all colors */
const int size = 3;
static  PageDesc* PageStrg[ size ]; // FIXME: 3 is a magic number, it is preferably to use a constant variable instead 

void PageStrgInit()
{
    memset( PageStrg, 0, (sizeof(PageStrg)) ); // FIXME: & is unnecessairy to use in sizeof(&PageStrg)
}

PageDesc* PageFind( void* ptr, char color )
{
    for (PageDesc* Pg = PageStrg[color]; Pg != NULL; Pg = Pg->next) // FIXME: check explicitly that Pg!= NULL 
                                                                    // FIXME: ';' was after "for()" => "if" would not be executed
        if (Pg->uKey == CALC_PAGE_KEY(ptr,color))
           return Pg;                                                                                                                                     
    return NULL;
}

PageDesc* PageReclaim( UINT cnt )
{
    UINT color = 0;
    PageDesc* Pg = PageStrg; // FIXME: pointer should be defined before being referenced
    while( cnt )
    {
        Pg = Pg->next;       
        PageRemove( PageStrg[ color ] );
        cnt--;
        if( Pg == NULL )
        {
            color++;
            if (color >= size) break; // FIXME: we cannot garantee that color would always less than size of PafeStrg array
                                      // (e.g., in case when cnt is so large that color will become > size). 
                                      // So it is better to check the value of color or to put assert() here.
            Pg = PageStrg[ color ];  
        }
    }
}
            
PageDesc* PageInit( void* ptr, UINT color )
{
    PageDesc* pg = (PageDesc*) malloc(sizeof(PageDesc));  // FIXME: "new" throws exception in case of bad allocation, 
                                                          //        but it doesn't return NULL
    if (pg != NULL)                 // FIXME: show explicitly that pg != NULL   
        PAGE_INIT(pg, ptr, color);  // FIXME: pg is already a pointer; &pg is wrong
    else {
        printf("Allocation has failed\n"); 
        exit(-1);                  // FIXME: exit right after allocation failure
    }
    return pg;
}

/**
 * Print all mapped pages
 */
void PageDump()
{
    UINT color = 0;
    #define PG_COLOR_NAME(clr) #clr
    char* PgColorName[] = 
    { 
        PG_COLOR_NAME(PG_COLOR_GREEN)   //FIXME: wrong consequence of colors 
        PG_COLOR_NAME(PG_COLOR_YELLOW),
        PG_COLOR_NAME(PG_COLOR_RED)
    };
                                    //FIXME: PG_COLOR_RED = 3, because numeration in enum starts from 1, but array PgColorName
    while( color < PG_COLOR_RED )  // has only 3 elements, so we can use only color = 0, 1, 2 as index
    {
        printf("PgStrg[(%u) %s] ********** \n", color, PgColorName[color] );  // FIXME: wrong order of format specificators
        for( PageDesc* Pg = PageStrg[color++]; Pg != NULL; Pg = Pg->next ) // FIXME: in case of "++color" usage we miss PageStrg[0] element
        {           
            if( Pg->cAddr == 0 ) // FIXME: uAddr is unsigned int type, not a pointer && FIXME: uAddr - wrong name of a field
                continue;

            printf("Pg :Key = 0x%o, addr %u\n", Pg->uKey, Pg->cAddr ); // FIXME: print cAddr as UINT, not as a pointer
                                                                       // FIXME: uAddr - wrong name of a field
        }
    }
    #undef PG_COLOR_NAME
}
